package net.zoneland.zrdp.framework.web.service.impl;


import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.richercloud.lift.util.function.enhancer.FunctionEnhancer;

import net.zoneland.oadocs.sdk.pojo.DocCreateRequest;
import net.zoneland.oadocs.sdk.pojo.DocDetailInfo;
import net.zoneland.oadocs.sdk.pojo.DocFileRequest;
import net.zoneland.oadocs.sdk.pojo.DocResponseInfo;
import net.zoneland.oadocs.sdk.pojo.DocResult;
import net.zoneland.oadocs.sdk.pojo.DocUploadRequest;
import net.zoneland.oadocs.sdk.pojo.PreviewRequest;
import net.zoneland.oadocs.sdk.service.impl.DocOnlineServiceClient;
import net.zoneland.oadocs.sdk.service.impl.DocServiceClient;
import net.zoneland.zrdp.framework.web.service.HttpClientService;
import net.zoneland.zrdp.framework.web.service.WpsAttachmentService;
import net.zoneland.zrdp.system.service.ISysConfigService;


/**
 * 后台附件操作服务.
 * @version v1.0
 */
@Service
public class WpsAttachmentServiceImpl implements WpsAttachmentService {
    /* 日志输出. */
    private static final Logger LOGGER = LoggerFactory.getLogger(WpsAttachmentServiceImpl.class);

    public static final String WPS_APP_KEY = "wps_app_key";
    /**
     * 请求成功状态码
     */
    private static final Integer SUCCEED = 200;

    /**
     * 默认根目录名称
     */
    private static final String ROOT = "根(%s)";

    /** 文件类型. */
    private static final String FILE_TYPE = "file";

    /*
    附件接口请求成功code
     */
    private static final int ATTACHMENT_SUCCESS_CODE = 1;

    // 普通文档操作服务，如：获取新的appKey、目录/文件的查询、创建、上传、删除、目录重命名、目录/文件复制、文件移动、批量下载等等.
    private final DocServiceClient docServiceClient;
    // 在线文档操作服务，如：在线预览、在线编辑等等，
    private final DocOnlineServiceClient docOnlineServiceClient;

    @Resource
    private ISysConfigService configService;
    @Resource
    private HttpClientService httpClientService;

    /**
     * 实例化后台附件操作对象.
     * @author pbody
     * @param serviceUrl 调用地址
     * @param attSysEcmAppId 应用ID
     */
    public WpsAttachmentServiceImpl(@Value("${attachment.serviceUrl}") final String serviceUrl,
                                    @Value("${attachment.attSysEcmAppId}") final String attSysEcmAppId) {
        docServiceClient = new DocServiceClient(serviceUrl, attSysEcmAppId);
        docOnlineServiceClient = new DocOnlineServiceClient(serviceUrl, attSysEcmAppId);
        LOGGER.info(">>>>>>>>>>>>>>>完成后台附件接口参数的初始化[{}],[{}]", serviceUrl, attSysEcmAppId);
    }

    /**
     * 获取最新的appKey.
     *
     * @param oldAppKey 老的appKey
     * @return java.lang.String
     */
    @Override
    public String getNewAppKey(final String oldAppKey) {
        return docServiceClient.getAppKey(oldAppKey).getData();
    }

    /**
    * 获取缓存中的appKey.
    * @return java.lang.String
    */
    @Override
    public String getCurrentAppKey() {
        return configService.selectConfigByKey(WPS_APP_KEY);
    }

    /**
     * 单文件上传.
     *
     * @param file 附件
     * @param fileId 原文件ID
     * @param folderId 文件夹ID
     * @return java.lang.String wps上的文件id
     * @throws IOException 异常
     */
    public String upload(final MultipartFile file, final String fileId, final String folderId) throws IOException {
        if (null == file) {
            return StringUtils.EMPTY;
        }

        // 初始化上传请求参数
        final String fileName = file.getOriginalFilename();
        final DocUploadRequest docUploadRequest = new DocUploadRequest();
        docUploadRequest.setFileName(fileName);
        docUploadRequest.setParentId(folderId);
        docUploadRequest.setFileId(StringUtils.defaultIfBlank(fileId, StringUtils.EMPTY));
        docUploadRequest.setUpdate(StringUtils.isNotBlank(fileId));
        // 添加附件上传请求
        final List<DocUploadRequest> docUploadRequestList = Collections.singletonList(docUploadRequest);

        // 设置文件请求参数
        final DocFileRequest docFileRequest = new DocFileRequest();
        docFileRequest.setAttrName(fileName);
        docFileRequest.setFileName(fileName);
        docFileRequest.setInputStream(file.getInputStream());
        // 添加文件请求
        final List<DocFileRequest> docFileRequestList = Collections.singletonList(docFileRequest);

        // 上传附件到服务器
        final String appKey = getCurrentAppKey();
        final DocResult<List<DocDetailInfo>> docResult = docServiceClient.upload(appKey, docUploadRequestList, docFileRequestList);

        // 处理上传结果 处理成功，返回文件的ID
        if (ATTACHMENT_SUCCESS_CODE == docResult.getCode() && CollectionUtils.isNotEmpty(docResult.getData())) {
            return docResult.getData().stream()
                .map(DocDetailInfo::getId)
                .findFirst() // wps附件接口返回数据格式是List，只上传一个文件List中就只会有一个文件信息
                .orElse(StringUtils.EMPTY);
        }

        return StringUtils.EMPTY; // 默认返回空字符串

    }

    /**
     * 根据目录id获取该id其下所有的文件，包含子目录下的文件，注意：可能速度会比较慢.
     * @param folderId 目录ID
     * @return 所有文件的列表
     */
    @Override
    public List<DocDetailInfo> getAttachmentsByPid(final String folderId) {
        final DocResult<List<DocDetailInfo>> docResult = docServiceClient.getFileTreeByPid(getCurrentAppKey(), folderId);
        return docResult.getData();
    }

    /**
     * 创建文件或者文件夹
     * @param createRequest 需要创建的信息
     * @return 文件或文件夹的id
     */
    @Override
    public String createFileOrFolder(final DocCreateRequest createRequest) {
        if(StringUtils.isBlank(createRequest.getFileName())){
            createRequest.setFileName(String.format(ROOT, RandomStringUtils.randomAlphabetic(24)));
        }
        final DocResult<DocResponseInfo> fileOrFolder = docServiceClient.createFileOrFolder(getCurrentAppKey(), createRequest);
        final Integer status = fileOrFolder.getStatus();
        if(null != status && status.equals(SUCCEED)){
            return fileOrFolder.getData().getFileId();
        }
        return StringUtils.EMPTY;
    }

    /**
     * 据附件fileId获取预览链接.
     * @author helu
     * @Date 16:21 2024/3/11
     * @param fileId 附件ID
     * @return java.lang.String
     */
    @Override
    public String getPreviewLink(final String fileId) {
        final PreviewRequest previewRequest = new PreviewRequest();
        previewRequest.setLoginAuth(true);
        return docServiceClient.getPreviewLink(getCurrentAppKey(),
            fileId, previewRequest).getData();
    }

    /**
     * 据附件fileId获取下载链接.
     * @author helu
     * @Date 16:21 2024/3/11
     * @param fileId 附件ID
     * @return java.lang.String
     */
    @Override
    public String getDownloadLink(final String fileId) {
        return docServiceClient.getDownloadLink(getCurrentAppKey(), fileId).getData();
    }

    /**
     * 批量删除附件.
     * @author helu
     * @Date 16:33 2024/3/11
     * @param fileId 附件ID，多值用,隔开
     * @return java.lang.String
     */
    @Override
    public int deleteFiles(final String fileId) {
        return docServiceClient.deleteById(getCurrentAppKey(), fileId).getCode();
    }

    /**
     * 获取文件夹下的第一个文件.
     * @author helu
     * @Date 10:55 2024/3/20
     * @param folderId 文件夹ID
     * @return net.zoneland.oadocs.sdk.pojo.DocDetailInfo
     */
    @Override
    public DocDetailInfo getOneFileByFolderId(final String folderId) {
        final DocResult<List<DocDetailInfo>> docResult = docServiceClient.getFileListByPid(getCurrentAppKey(), folderId);
        return Optional.ofNullable(docResult)
            .map(DocResult::getData)
            .map(Collection::stream)
            .orElseGet(Stream::empty)
            .filter(FunctionEnhancer.with(DocDetailInfo::getType).thenTest(FILE_TYPE::equals))
            .findFirst()//文档管理接口返回的是文件夹和文件列表，但是这边只要取第一个文件
            .orElseGet(DocDetailInfo::new);

    }

    /**
     * 获取文件夹下第一个文件的下载地址.
     * @author helu
     * @Date 11:16 2024/3/20
     * @param folderId 文件夹ID
     * @return 下载地址
     */
    public String getDownUrlByFolder(final String folderId) {
        return Optional.ofNullable(folderId)
            .filter(StringUtils::isNotBlank)
            .map(this::getOneFileByFolderId)
            .map(DocDetailInfo::getId)
            .filter(StringUtils::isNotBlank)
            .map(this::getDownloadLink)
            .orElse(StringUtils.EMPTY);
    }
}
